#include "tools.h"
#include "myinet.h"
#include <pthread.h>
#include <string.h>

/**
 * 一个使用线程实现的tcp echo server
 */

#define INTERVAL 5
#define BUFSIZE 4096

/// 用于监控的结构体
struct {
    pthread_mutex_t st_mutex; //!< 互斥锁
    unsigned st_conconut; //!< 连接计数
    unsigned st_contotal; //!< 已完成的连接
    unsigned long st_contime; //!< 连接总时间
    unsigned long st_bytecount; //!< 发送总byte
} stats;

/// 监控函数
/**
 * @note this function never returns
 */
void*
prstats(void* arg) {
    time_t now;
    while (1) {
        sleep(INTERVAL);
        // 获取互斥锁
        pthread_mutex_lock(&stats.st_mutex);

        // 输出相关信息
        time(&now);

        // 不用ctime，不想要newline
        //info("time: %s", ctime(&now));
        char time_str[20] = {0};
        struct tm* p = localtime(&now);
        strftime(time_str, sizeof(time_str), "%F %T", p);
        info("%s", time_str);
        info("%-32s: %u", "Current connection", stats.st_conconut);
        info("%-32s: %u", "Total connection", stats.st_contotal);
        info("%-32s: %u", "byte count", stats.st_bytecount);
        info("%-32s: %.2f\n", "average byte count",
                (float)stats.st_bytecount/stats.st_contotal);

        // 释放锁
        pthread_mutex_unlock(&stats.st_mutex);
    }
}


void*
handle_request(int sockfd) {
    printf("created\n");
    char buf[BUFSIZE];
    int size = -1;
    time_t start = time(0);
    int sendsize = 0;

    // 递增连接数
    pthread_mutex_lock(&stats.st_mutex);
    stats.st_conconut++;
    pthread_mutex_unlock(&stats.st_mutex);

    // 等1s，不发数据就关了
    struct timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    //setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
    
    // 不管客户端发多少数据
    while ( (size=read(sockfd, buf, BUFSIZE)) > 0) {
        if ((sendsize=write(sockfd, buf, size)) < 0) {
            error("error writing to socket");
            break;
        }
        pthread_mutex_lock(&stats.st_mutex);
        stats.st_bytecount += sendsize;
        pthread_mutex_unlock(&stats.st_mutex);
    }

    printf("handler done\n");

    close(sockfd);
    pthread_mutex_lock(&stats.st_mutex);
    stats.st_contotal ++;
    stats.st_contime += time(0) - start;
    stats.st_conconut --;
    pthread_mutex_unlock(&stats.st_mutex);


    pthread_exit(0);

    return NULL;
}

/**
 * @param portNumber echo server 的监听端口
 * @note this function never returns
 */
void
setup_echo(int portNumber) {

    pthread_t thread;
    pthread_attr_t attr;

    // 设置线程属性
    pthread_attr_init(&attr);
    // detach 表示这个线程不能使用pthread_join合并到一起
    // 这在作为daemon时是有用的
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    // 初始化锁
    pthread_mutex_init(&stats.st_mutex, 0);

    // 启动监听线程
    pthread_create(&thread, &attr, prstats, NULL);
    
    int sockfd;
    int newsockfd;
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    bzero(&addr, addrlen);


    sockfd = get_server_socket(portNumber, SOCK_STREAM, 32);

    if (sockfd < 0) {
        error_exit("get_server_socket", "error get socket");
    }
    info("got socket");

    info("listening to port: %d", portNumber);
    while ( (newsockfd=accept(sockfd,(struct sockaddr*)&addr,&addrlen)) > 0) {
        // 分配给线程
        if (pthread_create(&thread, &attr, (void* (*)(void*)) handle_request,
                    (void*)newsockfd) < 0) {
            error_exit("pthread_create", "error create thread");
        }
    }

    error_exit("", "server stopped");
}

int
main(int argc, char** argv){


    if (argc < 2){
        fprintf(stderr, "usage: %s <port> \n", argv[0]);
        exit(-1);
    }

    int portNumber = atoi(argv[1]);

    setup_echo(portNumber);
}
